#pragma once

#include "stdafx.h"
#include "DeciplineCompositor.h"
#include "EmptyDecipline.h"
#include "OccupyDecipline.h"
#include "KeepDecipline.h"
#include "TestAssert.h"

class DeciplineCompositorTest
{
public:
	DeciplineCompositorTest(void);
	virtual ~DeciplineCompositorTest(void);
	void run()
	{
		setUp();
		occupyDeciplineTest();
		std::cout << ".";
		keepDeciplineTest();
		std::cout << ".";
		emptyDeciplineTest();
		std::cout << ".";
		std::cout << std::endl;
	}
protected:
	void setUp()
	{
		decipline.addDecipline(new OccupyDecipline());
		decipline.addDecipline(new EmptyDecipline());
		decipline.addDecipline(new KeepDecipline());
	}
	/*
	*  Select any three squares and set to 1, 
	*  with the middle square with value 1.
	*  Apply decipline.
	*/
	void occupyDeciplineTest()
	{
		Matrix<int> tmp(3, 3);
		tmp.at(4) = 1;
		for (size_t i = 0; i != 9 && i != 4; ++i)
		{
			tmp.at(i) = 1;
			for (size_t j = i + 1; j != 9 && j != 4; ++j)
			{
				tmp.at(j) = 1;
				for (size_t k = j + 1; k != 9 && k != 4; ++k)
				{
					tmp.at(k) = 1;
					HANDYTEST_ASSERT(decipline.useDeciplines(tmp) == 1);
					tmp.at(k) = 0;
				}
				tmp.at(j) = 0;
			}
			tmp.at(i) = 0;
		}
	}
	/*
	*  Select any two squares and set to 1, 
	*  with the middle square with value range from 0 to 1.
	*  Apply decipline.
	*/
	void keepDeciplineTest()
	{
		Matrix<int> tmp(3, 3);
		for (int val = 0; val != 2; ++val)
		{
			tmp.at(4) = val;
			for (size_t i = 0; i != 9 && i != 4; ++i)
			{
				tmp.at(i) = 1;
				for (size_t j = i + 1; j != 9 && j != 4; ++j)
				{
					tmp.at(j) = 1;
					HANDYTEST_ASSERT(decipline.useDeciplines(tmp) == tmp.at(4));
					tmp.at(j) = 0;
				}
				tmp.at(i) = 0;
			}
		}
	}
	/*
	*  Select squares but not two or three and set them to 1, 
	*  with the middle square with value range from 0 to 1.
	*  Apply decipline.
	*/
	void emptyDeciplineTest()
	{
		Matrix<int> tmp(3, 3);
		//Test empty neighbors.
		for (int val = 0; val != 2; ++val)
		{
			tmp.at(4) = val;
			HANDYTEST_ASSERT(decipline.useDeciplines(tmp) == 0);
		}
		for (int val = 0; val != 2; ++val)
		{
			tmp.at(4) = val;
			for (int i1 = 0; i1 != 9 && i1 != 4; ++i1)
			{
				tmp.at(i1) = 1;
				HANDYTEST_ASSERT(decipline.useDeciplines(tmp) == 0);
				for (int i2 = i1+1; i2 != 9 && i2 != 4; ++i2)
				{
					tmp.at(i2) = 1;
					for (int i3 = i2+1; i3 != 9 && i3 != 4; ++i3)
					{
						tmp.at(i3) = 1;
						for (int i4 = i3+1; i4 != 9 && i4 != 4; ++i4)
						{
							tmp.at(i4) = 1;
							HANDYTEST_ASSERT(decipline.useDeciplines(tmp) == 0);
							for (int i5 = i4+1; i5 != 9 && i5 != 4; ++i5)
							{
								tmp.at(i5) = 1;
								HANDYTEST_ASSERT(decipline.useDeciplines(tmp) == 0);
								for (int i6 = i5+1; i6 != 9 && i6 != 4; ++i6)
								{
									tmp.at(i6) = 1;
									HANDYTEST_ASSERT(decipline.useDeciplines(tmp) == 0);
									for (int i7 = i6+1; i7 != 9 && i7 != 4; ++i7)
									{
										tmp.at(i7) = 1;
										HANDYTEST_ASSERT(decipline.useDeciplines(tmp) == 0);
										for (int i8 = i7+1; i8 != 9 && i8 != 4; ++i8)
										{
											tmp.at(i8) = 1;
											HANDYTEST_ASSERT(decipline.useDeciplines(tmp) == 0);
											for (int i9 = i5+1; i8 != 9 && i9 != 4; ++i9)
											{
												tmp.at(i9) = 1;
												HANDYTEST_ASSERT(decipline.useDeciplines(tmp) == 0);
												tmp.at(i9) = 0;
											}
											tmp.at(i8) = 0;
										}
										tmp.at(i7) = 0;
									}
									tmp.at(i6) = 0;
								}
								tmp.at(i5) = 0;
							}
							tmp.at(i4) = 0;
						}
						tmp.at(i3) = 0;
					}
					tmp.at(i2) = 0;
				}
				tmp.at(i1) = 0;
			}
		}
	}
private:
	DeciplineCompositor decipline;
};
